package helpers

import (
	"encoding/json"
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	log "github.com/jeanphorn/log4go"
)

const (
	//SecretKey token默认安全码
	SecretKey = "LightPlayerServer8080"
)

//JwtCustomClaims Token
//Payload 结构体
type JwtCustomClaims struct {
	jwt.StandardClaims `json:"claims"`
	//追加自己需要的信息
	//时间
	TokenTime string `json:"token_time"`
	//用户id
	UID uint `json:"uid"`
	//是否为管理员
	Admin bool `json:"admin"`
}

//IsEmpty 判断字符串去掉首尾空格后是否为空，返回一个bool
func IsEmpty(data string) bool {
	return len(strings.Trim(data, " ")) <= 0
}

//IsContentPass 检查内容是否合法
func IsContentPass(content, contentType string) (result bool) {
	result = false
	regStr := ``
	switch contentType {
	//验证邮箱格式
	case "email":
		regStr = `^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$`
	//验证电话格式
	case "tel":
		regStr = `^[1][3,4,5,7,8][0-9]{9}$`

	case "password":
		regStr = `^\s*[a-zA-Z0-9_!@]{6,16}$`
	}

	reg := regexp.MustCompile(regStr)
	if reg == nil {
		log.LOGGER("SERVER").Error("创建校验器失败")
		return
	}

	regResult := reg.FindAllString(content, -1)
	if len(regResult) > 0 {
		log.LOGGER("SERVER").Info("%s:内容通过校验", contentType)
		result = true
	} else {
		log.LOGGER("SERVER").Info("%s:内容未通过校验", contentType)
	}

	return
}

//CreateMsg 创建从服务器返回客户端的信息
func CreateMsg(code int, msg string, data interface{}) string {
	msgMap := make(map[string]interface{})
	msgMap["code"] = code
	msgMap["msg"] = msg
	msgMap["data"] = data

	re, err := json.Marshal(msgMap)
	if err != nil {
		log.LOGGER("SERVER").Error("生成JSON失败")
		return ""
	}

	return string(re)
}

//CreateToken 生成Token
//SecretKey是一个 const 常量
func CreateToken(issuer string, UID uint, isAdmin bool) (string, error) {
	//创建一个新的令牌对象，指定签名方法和声明
	claims := &JwtCustomClaims{
		jwt.StandardClaims{
			ExpiresAt: int64(time.Now().Add(time.Hour * 72).Unix()),
			Issuer:    issuer,
		},
		strings.Split(time.Now().Local().String(), ".")[0],
		UID,
		isAdmin,
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	//使用密钥签名并获得完整的编码令牌作为字符串
	tokenString, err := token.SignedString([]byte(SecretKey))

	return tokenString, err
}

//ParseToken 解析token
//解析使用令牌字符串和一个用于查找密钥的函数。
//后者尤其如此
//如果您对应用程序使用多个键，则很有用。
//标准是在令牌头以标识要使用的密钥，但提供了已解析的令牌（头和声明）回调，提供了灵活性。
func ParseToken(tokenStr string) (map[string]interface{}, error) {
	token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
		return []byte(SecretKey), nil
	})

	//验证alg是否符合期望
	if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
		log.LOGGER("SERVER").Error("解析Token时意外的方法: %v", token.Header["alg"])
		return nil, fmt.Errorf("解析Token时意外的方法: %v", token.Header["alg"])
	}

	//进行断言
	result, ok := token.Claims.(jwt.MapClaims)
	if !ok {
		log.LOGGER("SERVER").Error("解析token时，断言结果类型失败")
	}

	return result, err
}

//CutToken 截取token末尾部分的前10位
func CutToken(token string) string {
	t := strings.Split(token, ".")[2]
	return t[0:10]
}

//TestCreateToken 测试token的生成与解析
// func TestCreateToken() {
// 	fmt.Println("生成Token")
// 	token, errCreate := CreateToken("issuer", 0, false)
// 	if errCreate != nil {
// 		fmt.Println("生成token失败:", errCreate)
// 		return
// 	}
// 	fmt.Println("生成的token:", token)

// 	fmt.Println("开始解析Token")
// 	result, errParse := ParseToken(token)
// 	if errParse != nil {
// 		fmt.Println("解析token失败:", errParse)
// 		return
// 	}
// 	fmt.Println("token的解析结果:", result)
// }
